package org.nobject.common.apps;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import org.nobject.common.file.FileUtils;
import org.nobject.common.lang.StringUtils;


/**
 * 对资源打包Utils
 *
 * @author bianrongjun
 * @version 1.0
 */
public class PackUtils implements Serializable{
	
	/** 打包文件名称 */
	public static String packBin="DATA.BIN";
	
	/** packHeadjar */
	public static String packHeadjar="$packhead.jar";
	
	/** 
	 * 打包指定WEB-INF目录下的资源
	 * @param webinfoPath
	 * @throws Exception
	 */
	public static void packByWebinfopath(String webinfoPath)throws Exception{
		System.out.println(webinfoPath);
		pack(webinfoPath+"/classes",webinfoPath+"/"+packBin,webinfoPath+"/lib/"+packHeadjar);
	}
	
	/** 
	 * 打包
	 * @param sourcePath
	 * @param binPath
	 * @param libsPath
	 */
	public static void pack(String sourcePath,String binPath,String libsPath){
		try {
			PackUtils pack=new PackUtils();
			Set<String> ps=FileUtils.getSubFilePathes(sourcePath,new String[]{".*\\.class",".*\\.xml"},true);
			
			//BIN
			FileOutputStream bin_fos=new FileOutputStream(binPath);
			ObjectOutputStream bin_oos = new ObjectOutputStream(bin_fos);
			
			//HeadJar
			ByteArrayOutputStream hj_bos=new ByteArrayOutputStream();
			JarOutputStream hj_os = new JarOutputStream(hj_bos);
			
			for(String p:ps){
				String ext=FileUtils.getFileExtension(p);
				String className=null;
				String classPath=null;
				byte[] bs=FileUtils.read2Bytes(p);
				if(ext.equals("class")){
					className=p.substring(sourcePath.length()).replaceAll("[\\\\/]", ".");
					className=StringUtils.removeStart(className, ".");
					className=StringUtils.removeEnd(className, ".class");
					pack.addClass(className, bs);
					
					CtClass cc=ClassPool.getDefault().makeClass(new ByteArrayInputStream(bs));
					CtMethod[] ms= cc.getDeclaredMethods();
					for(CtMethod m:ms){
						String mBody="";
						if(m.getReturnType().getName().equals("void")) mBody="return;";
						else mBody="return null;";
						m.setBody(mBody);
					}

					JarEntry entry = new JarEntry(className.replaceAll("\\.","/")+".class");
					hj_os.putNextEntry( entry );
					hj_os.write(cc.toBytecode());
					hj_os.flush();
					
					System.out.println(className);
				}else if(ext.equals("xml")){
					classPath=p.substring(sourcePath.length()).replaceAll("[\\\\/]", "/");
					classPath=StringUtils.removeStart(classPath, "/");
					pack.addBeanXmls(classPath, bs);
					System.out.println(classPath);
				}else{
					throw new RuntimeException("不支持该类型文件打包."+ext);
				}
			}
			//HeadJar
			hj_os.closeEntry();
			hj_os.close();
			FileUtils.makeFile(libsPath, hj_bos.toByteArray());
			
			//BIN
			bin_oos.writeObject(pack);
			bin_oos.flush();
			bin_oos.close();
			System.out.println("创建PACK>OK");
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	/** 
	 * 读取Pack
	 * @param path
	 */
	public static PackUtils read(String path) {
		try {
			FileInputStream fis = new FileInputStream(path);
			ObjectInputStream oin = new ObjectInputStream(fis);
			return (PackUtils) oin.readObject();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		
	}
	
	///////////////////////////////////////////////
	
	/** classes */
	public Map<String,byte[]> classes=new LinkedHashMap();
	
	/** beanXmls */
	public Map<String,byte[]> beanXmls=new LinkedHashMap();
	
	/** 
	 * addClass
	 * @param className
	 * @param classBytes
	 */
	private void addClass(String className,byte[] classBytes){
		classes.put(className, classBytes);
	}
	
	/** 
	 * addBeanXmls
	 * @param classPath
	 * @param classBytes
	 */
	private void addBeanXmls(String classPath,byte[] classBytes){
		beanXmls.put(classPath, classBytes);
	}
	
	/** 
	 * Ant打包入口
	 * @param args
	 */
	public static void main(String[] args) throws Exception{
		String classpath	=args[0];	//D:/WebRoot/WEB-INF
		String refClasspath	=args[1];	//D:/WebRoot/WEB-INF/classes;D:/WebRoot/WEB-INF/lib;D:/Tomcat/common/lib;
		String destDir		=args[2];	//D:/WebRoot/pack
		
		ClassPool cp= ClassPool.getDefault();
		cp.appendClassPath(classpath+"/classes");
		
		String[] classpaths=refClasspath.split(";");
		for(String p:classpaths){
			Set<String> pls=FileUtils.getSubFilePathes(p,new String[]{".*\\.jar"}, false);
			for(String pl:pls){
				cp.appendClassPath(pl);
			}
		}
//		String source="D:/WOR_HOME/ECLIPSE_WORKSPACE/ppm_rv/trunk/WebRoot/WEB-INF/classes";//args[0];
//		String dest="C:/DATA.BIN";//args[0];
		pack(classpath,destDir+"/"+packBin,destDir+"/"+packHeadjar);
	}
}
